#include "rule.h"
#include "define.h"

bool CSrcSubTree::SaveToFile( char *fn )
{
	FILE *fp = fopen( fn, "w" );
	if( fp == NULL )	return false;

	if( SaveToFile( fp ) == false )	{
		fclose( fp );
		return false;
	}
	return true;
}

bool CSrcSubTree::SaveToFile( FILE *fp )	
{
	if( fp == NULL )	return false;

	fprintf( fp, "### [src]\t[freq]\t[cross]\n" );
	int num=0;
	map<string, CSrcSubTree>::iterator itr = stree_map.begin();
	while( itr != stree_map.end() )	{
		CSrcSubTree &r = itr->second;
		fprintf( fp, "%s\t%d\t%d\n", r.before.GetStr(), r.freq, r.num_cross );
		itr++;
	}
	return true;
}

void CSrcSubTree::Add( CUString before, int num_cross )
{
	string b = before.GetStr();
	map<string, CSrcSubTree>::iterator itr = stree_map.find( b );
	if( itr == stree_map.end() )	{
		CSrcSubTree new_src;
		new_src.Set( before, 1, num_cross );
		stree_map[b] = new_src;
	}
	else	{
		CSrcSubTree &r = itr->second;
		(r.freq)++;
		(r.num_cross)+=num_cross;
	}
}


int CSrcSubTree::GetFreq( CUString str )
{
	string key = str.GetStr();
	map<string, CSrcSubTree>::iterator itr = stree_map.find( key );
	if( itr == stree_map.end() )	return 0;

	return itr->second.freq;
}

/*
void CRuleInit::Add( CUString before, CUString after, int before_cross, int after_cross )
{
	string b = before.GetStr();
	string a = after.GetStr();
	CUString key = before + CUString("->") + after;
	string k = key.GetStr();


	map<string, CRuleInit>::iterator itr = rule_map.find( k );
	if( itr == rules.end() )	{
		CRuleInit new_rule;
		new_rule.Set( before, after, before_cross, after_cross, 1 );
		rules[k] = new_rule;
	}
	else	{
		CRuleInit &r = itr->second;
		r.before_cross += before_cross;
		r.after_cross += after_cross;
		(r.freq)++;
	}
}
*/

/*
void CRuleSet::AddRuleInit( CUString before, CUString after, int before_cross, int after_cross )
{
	string b = before.GetStr();
	string a = after.GetStr();
	CUString key = before + CUString("->") + after;
	string k = key.GetStr();


	map<string, CRuleInit>::iterator itr = rules_init.find( k );
	if( itr == rules_init.end() )	{
		CRuleInit new_rule;
		new_rule.Set( before, after, before_cross, after_cross, 1 );
		rules_init[k] = new_rule;
	}
	else	{
		CRuleInit &r = itr->second;
		r.before_cross += before_cross;
		r.after_cross += after_cross;
		(r.freq)++;
	}
}
*/

//////////////////////////////////////////////////////////////////////////////
bool CRuleCross::LoadRule( char *fn, int cross_red_th )
{
	CUTextFile file( fn );
	if( file.IsOpen() == false )	{
		fprintf( stderr, "ERROR: file open fail %s\n", fn );
		return false;
	}

	CUString content;
	file.LoadToStr( content );
	CUStringListSN ls( content, "\n" );
	int num_line = 0;

	for( int i=0; i<ls.GetSize(); i++ )	{
		CUString str = ls.GetAt(i);
		if( str.Find( "###" ) == 0 )	continue;
		if( str.IsEmpty() )	continue;
		num_line++;

		CUStringListSN tok( str, "\t" );
		if( tok.GetSize() != 7 )	{
			fprintf( stderr, "invalid rule cr file (not 7 column) %d\n", tok.GetSize() );
			return false;
		}

		CRuleCross new_rule;
		new_rule.before = tok.GetAt(0);
		new_rule.after = tok.GetAt(2);
		new_rule.before_cross = atoi( tok.GetAt(3) );
		new_rule.after_cross = atoi( tok.GetAt(4) );
		new_rule.freq = atoi( tok.GetAt(6) );

		if( new_rule.before_cross - new_rule.after_cross < cross_red_th )	continue;
//		if( new_rule.freq <= 1 )	continue;

		this->Add( new_rule );
	}

	return true;
}


void CRuleCross::Add( CRuleCross &add_rule )
{
	string before = add_rule.before.GetStr();
	string after = add_rule.after.GetStr();
	string k = before + string("->") + after;


	map<string, CRuleCross>::iterator itr = rule_map.find( k );
	if( itr == rule_map.end() )	{
		/*
		CRuleCross new_rule;
		new_rule.Set( (char*)before.c_str(), (char*)after.c_str(),
						add_rule.before_cross, add_rule.after_cross, add_rule.freq, add_rule.prob );
		rule_map[k] = new_rule;
		*/
		rule_map[k] = add_rule;

	}
	else	{
		CRuleCross &r = itr->second;
		r.before_cross += add_rule.before_cross;
		r.after_cross += add_rule.after_cross;
		(r.freq) += add_rule.freq;

	}
}



bool CRuleCross::SaveToFile( FILE *fp, CSrcSubTree &stree )	
{
	fprintf( fp, "### before\t->\tafter\tb_cross\ta_cross\tcross_red\tcnt\n" );
		int num=0;
		map<string, CRuleCross>::iterator itr = rule_map.begin();
		while( itr != rule_map.end() )	{
			CRuleCross &r = itr->second;

			int cross_red = r.before_cross - r.after_cross;
			int total_cnt = stree.GetFreq( r.before );
			float prob = (float)r.freq / (float)total_cnt;

/*
			fprintf( fp, "%s\t%s\t%d\t%d\t%d\t%d\t%d\t%1.6f\n",
					r.before.GetStr(), r.after.GetStr(),
					r.before_cross, r.after_cross, cross_red, r.freq, total_cnt, prob);
			*/

/*
			if( cross_red <= 0 )	{
				itr++;
				continue;
			}
*/
			fprintf( fp, "%s\t->\t%s\t%d\t%d\t%d\t%d\n",
					r.before.GetStr(), r.after.GetStr(),
					r.before_cross, r.after_cross, cross_red, r.freq );
			itr++;
		}

		return true;
}




// find one best
bool CRuleCross::FindRule( CUString rule_str, CRuleCross rule[], int &num_rule )
{
	num_rule = 0;

	int max_freq = -1;
	map<string, CRuleCross>::iterator itr = rule_map.begin();
	while( itr != rule_map.end() )	{
		CRuleCross &r = itr->second;
		if( itr->second.before == rule_str )	{
			if( itr->second.freq > max_freq )	{
				max_freq = itr->second.freq;
			}
		}
		itr++;
	}

	if( max_freq == -1 )	return false;


	itr = rule_map.begin();
	while( itr != rule_map.end() )	{
		CRuleCross &r = itr->second;
		if( itr->second.before == rule_str &&
			itr->second.freq == max_freq )	{
			rule[num_rule] = itr->second;
			itr->second.is_best = true;
			num_rule++;
			return true;
		}
		itr++;
	}

	return false;

/*
	map<string, CRuleInit>::iterator itr = rules_init.begin();
	while( itr != rules_init.end() )	{
		CRuleInit &r = itr->second;
		if( itr->second.before == rule_str )	{
			rule[num_rule] = itr->second;
			num_rule++;
		}
		itr++;
	}
	return true;
	*/
}










void CRuleRF::Add( CRuleRF &add_rule )
{
	string before = add_rule.before.GetStr();
	string after = add_rule.after.GetStr();
	string k = before + string("->") + after;

	map<string, CRuleRF>::iterator itr = rule_map.find( k );
	if( itr == rule_map.end() )	{
		rule_map[k] = add_rule;
	}
	else	{
		CRuleRF &r = itr->second;
		(r.freq) += add_rule.freq;

	}
}


bool CRuleRF::SaveToFile( FILE *fp, CSrcSubTree &stree, bool only_reorder_best )	
{
	fprintf( fp, "### before\t->\tafter\tcnt\ttot_cnt\tprob\treorder\tbest\n" );
	int num=0;
	map<string, CRuleRF>::iterator itr = rule_map.begin();
	while( itr != rule_map.end() )	{
		CRuleRF &r = itr->second;

		if( only_reorder_best == true )	{
			if( r.is_best == false )	{
				itr++;
				continue;
			}
			if( r.IsReorder() == false )	{
				itr++;
				continue;
			}
		}

		int total_cnt = r.total_cnt;
		if( total_cnt == NULL_NUM )	{
			total_cnt = stree.GetFreq( r.before );
		}
		float prob = (float)r.freq / (float)total_cnt;

		fprintf( fp, "%s\t->\t%s\t%d\t%d\t%1.6f\t", 
				r.before.GetStr(), r.after.GetStr(), r.freq, total_cnt, prob );
		if( r.IsReorder() == true )	{
			fprintf( fp, "O\t" );
		}
		else {
			fprintf( fp, "X\t" );
		}

		if( r.is_best == true )	{
			fprintf( fp, "O\n" );
		}
		else	{
			fprintf( fp, "X\n" );
		}
		itr++;
	}

	return true;
}

bool CRuleRF::SaveToEvalFile( FILE *fp )
{
	//              1         2     3       4           5             6       
	fprintf( fp, "### before\t->\tafter\teval_cnt\teval_tot_cnt\teval_prec\n" );
	int num=0;
	map<string, CRuleRF>::iterator itr = rule_map.begin();
	while( itr != rule_map.end() )	{
		CRuleRF &r = itr->second;

/*
		if( r.eval_apply_cnt == 0 )	{
			itr++;
			continue;
		}
		*/

		/*
		if( only_reorder_best == true )	{
			if( r.is_best == false )	{
				itr++;
				continue;
			}
			if( r.IsReorder() == false )	{
				itr++;
				continue;
			}
		}
		*/

		int total_cnt = r.total_cnt;
		float prec = -1;
		if( r.eval_apply_cnt > 0 )	{
			prec = (float)r.eval_correct_cnt / (float)r.eval_apply_cnt;
		}

		//             1  2   3   4   5    6
		fprintf( fp, "%s\t->\t%s\t%d\t%d\t%1.6f\n", 
				r.before.GetStr(), r.after.GetStr(), r.eval_correct_cnt, r.eval_apply_cnt, prec );

		itr++;
	}

	return true;
}


bool CRuleRF::FindRule( CUString rule_str, CRuleRF rule[], int &num_rule )
{
	num_rule = 0;

	double max_prob = -1.0;
	map<string, CRuleRF>::iterator itr = rule_map.begin();
	while( itr != rule_map.end() )	{
		CRuleRF &r = itr->second;
		if( itr->second.before == rule_str )	{
			if( itr->second.prob > max_prob)	{
				max_prob = itr->second.prob;
			}
		}
		itr++;
	}

	if( max_prob == -1.0 )	return false;


	itr = rule_map.begin();
	while( itr != rule_map.end() )	{
		CRuleRF &r = itr->second;
		if( itr->second.before == rule_str &&
			itr->second.prob == max_prob )	{
			rule[num_rule] = itr->second;
			itr->second.is_best = true;
			num_rule++;
			return true;
		}
		itr++;
	}

	return false;

}



//////////////////////////////////////////////////////////////////////////////
bool CRuleRF::LoadRule( char *fn, int freq_th, double prob_th )
{
	CUTextFile file( fn );
	if( file.IsOpen() == false )	{
		fprintf( stderr, "ERROR: file open fail %s\n", fn );
		return false;
	}


	CUString content;
	file.LoadToStr( content );
	CUStringListSN ls( content, "\n" );
	int num_line = 0;

	for( int i=0; i<ls.GetSize(); i++ )	{
		CUString str = ls.GetAt(i);
		if( str.Find( "###" ) == 0 )	continue;
		if( str.IsEmpty() )	continue;
		num_line++;

		CUStringListSN tok( str, "\t" );
		if( tok.GetSize() != 8 )	{
			fprintf( stderr, "invalid rule rf file (not 8 column) %d\n", tok.GetSize() );
			return false;
		}

		CRuleRF new_rule;
		new_rule.before = tok.GetAt(0);
		new_rule.after = tok.GetAt(2);
		new_rule.freq = atoi( tok.GetAt(3) );
		new_rule.total_cnt= atoi( tok.GetAt(4) );
		new_rule.prob = atof( tok.GetAt(5) );

		if( new_rule.freq < freq_th )	continue;
		if( new_rule.prob < prob_th )	continue;

		this->Add( new_rule );
	}

	return true;
}


